package com.beiing.leafchat.renderer;


import com.beiing.leafchat.bean.Axis;
import com.beiing.leafchat.bean.ChartData;
import com.beiing.leafchat.bean.Line;
import com.beiing.leafchat.bean.PointValue;
import com.beiing.leafchat.support.LeafUtil;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.LinearShader;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PathEffect;
import ohos.agp.render.PathMeasure;
import ohos.agp.render.Shader;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.app.Context;

import java.util.List;

import static ohos.agp.render.Paint.ShaderType.LINEAR_SHADER;

/**
 * Created by chenliu on 2017/1/9.<br/>
 * 描述：
 * </br>
 */

public class LeafLineRenderer extends AbsRenderer {
    private static final float LINE_SMOOTHNESS = 0.16f;

    /**
     * 填充画笔
     **/
    private Paint fillPaint;

    private PathMeasure measure;

    /**
     * 动画结束标志
     */
    private boolean isAnimateEnd = true;

    /**
     * 是否开始绘制，防止动画绘制之前绘制一次
     */
    private boolean isShow;

    private float phase;

    private LinearShader fillShader;

    public LeafLineRenderer(Context context, Component view) {
        super(context, view);
    }

    @Override
    protected void initPaint() {
        super.initPaint();
        fillPaint = new Paint();
        fillPaint.setStyle(Paint.Style.FILL_STYLE);
    }

    /**
     * 画折线
     *
     * @param canvas 绘制信息
     * @param line 折线
     */
    public void drawLines(Canvas canvas, Line line) {
        if (line != null && isShow) {
            linePaint.setColor(new Color(line.getLineColor()));
            linePaint.setStrokeWidth(LeafUtil.dp2px(mContext, line.getLineWidth()));
            linePaint.setStyle(Paint.Style.STROKE_STYLE);
            List<PointValue> values = line.getValues();
            Path path = line.getPath();
            int size = values.size();
            for (int i = 0; i < size; i++) {
                PointValue point = values.get(i);
                if (i == 0) path.moveTo(point.getOriginX(), point.getOriginY());
                else path.lineTo(point.getOriginX(), point.getOriginY());
            }

            measure = new PathMeasure(path, false);
            linePaint.setPathEffect(createPathEffect(measure.getLength(), phase, 0.0f));
            canvas.drawPath(path, linePaint);

        }
    }


    /**
     * 画曲线
     *
     * @param canvas 绘制信息
     * @param line 曲线信息
     */
    public void drawCubicPath(Canvas canvas, Line line) {
        if (line != null && isShow) {
            linePaint.setColor(new Color(line.getLineColor()));
            linePaint.setStrokeWidth(LeafUtil.dp2px(mContext, line.getLineWidth()));
            linePaint.setStyle(Paint.Style.STROKE_STYLE);
            Path path = line.getPath();

            float prePreviousPointX = Float.NaN;
            float prePreviousPointY = Float.NaN;
            float previousPointX = Float.NaN;
            float previousPointY = Float.NaN;
            float currentPointX = Float.NaN;
            float currentPointY = Float.NaN;
            float nextPointX = Float.NaN;
            float nextPointY = Float.NaN;

            List<PointValue> values = line.getValues();
            final int lineSize = values.size();
            for (int valueIndex = 0; valueIndex < lineSize; ++valueIndex) {
                if (Float.isNaN(currentPointX)) {
                    PointValue linePoint = values.get(valueIndex);
                    currentPointX = linePoint.getOriginX();
                    currentPointY = linePoint.getOriginY();
                }
                if (Float.isNaN(previousPointX)) {
                    if (valueIndex > 0) {
                        PointValue linePoint = values.get(valueIndex - 1);
                        previousPointX = linePoint.getOriginX();
                        previousPointY = linePoint.getOriginY();
                    } else {
                        previousPointX = currentPointX;
                        previousPointY = currentPointY;
                    }
                }

                if (Float.isNaN(prePreviousPointX)) {
                    if (valueIndex > 1) {
                        PointValue linePoint = values.get(valueIndex - 2);
                        prePreviousPointX = linePoint.getOriginX();
                        prePreviousPointY = linePoint.getOriginY();
                    } else {
                        prePreviousPointX = previousPointX;
                        prePreviousPointY = previousPointY;
                    }
                }

                // nextPoint is always new one or it is equal currentPoint.
                if (valueIndex < lineSize - 1) {
                    PointValue linePoint = values.get(valueIndex + 1);
                    nextPointX = linePoint.getOriginX();
                    nextPointY = linePoint.getOriginY();
                } else {
                    nextPointX = currentPointX;
                    nextPointY = currentPointY;
                }

                if (valueIndex == 0) {
                    // Move to start point.
                    path.moveTo(currentPointX, currentPointY);
                } else {
                    // Calculate control points.
                    final float firstDiffX = LeafUtil.add(currentPointX, -prePreviousPointX);
                    final float firstDiffY = LeafUtil.add(currentPointY, -prePreviousPointY);
                    final float secondDiffX = LeafUtil.add(nextPointX, -previousPointX);
                    final float secondDiffY = LeafUtil.add(nextPointY, -previousPointY);
                    final float firstControlPointX = LeafUtil.add(previousPointX, LeafUtil.mul(LINE_SMOOTHNESS, firstDiffX));
                    final float firstControlPointY = LeafUtil.add(previousPointY, LeafUtil.mul(LINE_SMOOTHNESS, firstDiffY));
                    final float secondControlPointX = LeafUtil.add(currentPointX, -LeafUtil.mul(LINE_SMOOTHNESS, secondDiffX));
                    final float secondControlPointY = LeafUtil.add(currentPointY, -LeafUtil.mul(LINE_SMOOTHNESS, secondDiffY));

                    if (currentPointY == previousPointY) {
                        path.lineTo(currentPointX, currentPointY);
                    } else {
                        path.cubicTo(new Point(firstControlPointX, firstControlPointY), new Point(secondControlPointX, secondControlPointY),
                                new Point(currentPointX, currentPointY));
                    }
                }

                // Shift values by one back to prevent recalculation of values that have
                // been already calculated.
                prePreviousPointX = previousPointX;
                prePreviousPointY = previousPointY;
                previousPointX = currentPointX;
                previousPointY = currentPointY;
                currentPointX = nextPointX;
                currentPointY = nextPointY;
            }

            measure = new PathMeasure(path, false);
            linePaint.setPathEffect(createPathEffect(measure.getLength(), 1, 0.0f));
            canvas.drawPath(path, linePaint);
        }
    }


    /**
     * 填充
     *
     * @param canvas 绘制信息
     * @param line 线条
     * @param axisX X轴
     */
    public void drawFillArea(Canvas canvas, Line line, Axis axisX) {
        //继续使用前面的 path
        if (line != null && line.getValues().size() > 1 && isShow) {
            List<PointValue> values = line.getValues();
            PointValue firstPoint = values.get(0);
            float firstX = firstPoint.getOriginX();

            Path path = line.getPath();
            PointValue lastPoint = values.get(values.size() - 1);
            float lastX = lastPoint.getOriginX();
            path.lineTo(lastX, axisX.getStartY());
            path.lineTo(firstX, axisX.getStartY());
            path.close();

            if (fillShader == null) {
                fillShader = new LinearShader(new Point[]{new Point(0, 0), new Point(0, mHeight)}, new float[]{}, new Color[]{new Color(line.getFillColor()), Color.TRANSPARENT}, Shader.TileMode.CLAMP_TILEMODE);
                fillPaint.setShader(fillShader, LINEAR_SHADER);
            }

            if (line.getFillColor() == 0)
                fillPaint.setAlpha(100);
            else
                fillPaint.setColor(new Color(line.getFillColor()));

            canvas.save();
            canvas.clipRect(firstX, 0, LeafUtil.add(LeafUtil.mul(phase, LeafUtil.add(lastX, -firstX)), firstX), mHeight);
            canvas.drawPath(path, fillPaint);
            canvas.restore();
            path.reset();
        }
    }

    /**
     * 画圆点
     *
     * @param canvas 绘制信息
     * @param line 圆点线条信息
     */
    public void drawPoints(Canvas canvas, Line line) {
        if (line != null && line.isHasPoints() && isShow) {
            List<PointValue> values = line.getValues();
            float radius = LeafUtil.dp2px(mContext, line.getPointRadius());
            float strokeWidth = LeafUtil.dp2px(mContext, 1);
            PointValue point;
            for (int i = 0, size = values.size(); i < size; i++) {
                point = values.get(i);
                labelPaint.setStyle(Paint.Style.FILL_STYLE);
                labelPaint.setColor(new Color(line.getPointColor()));
                canvas.drawCircle(point.getOriginX(), point.getOriginY(),
                        radius, labelPaint);
                labelPaint.setStyle(Paint.Style.STROKE_STYLE);
                labelPaint.setColor(Color.WHITE);
                labelPaint.setStrokeWidth(strokeWidth);
                canvas.drawCircle(point.getOriginX(), point.getOriginY(),
                        radius, labelPaint);
            }
        }
    }

    /**
     * 带动画的绘制
     *
     * @param duration 动画
     * @param v 源
     */
    public void showWithAnimation(Component v, int duration) {
//        isAnimateEnd = false;
//        AnimatorProperty animatorProperty = v.createAnimatorProperty();
//        animatorProperty.rotate(360).setDuration(duration)
//                .setStateChangedListener(new Animator.StateChangedListener() {
//                    @Override
//                    public void onStart(Animator animator) {
//
//                    }
//
//                    @Override
//                    public void onStop(Animator animator) {
//
//                    }
//
//                    @Override
//                    public void onCancel(Animator animator) {
//
//                    }
//
//                    @Override
//                    public void onEnd(Animator animator) {
//                        isAnimateEnd = true;
//                    }
//
//                    @Override
//                    public void onPause(Animator animator) {
//
//                    }
//
//                    @Override
//                    public void onResume(Animator animator) {
//
//                    }
//                });
//        animatorProperty.start();
        isAnimateEnd = true;
        isShow = true;
    }


    //showWithAnimation动画开启后会调用该方法
    public void setPhase(float phase) {
        chartView.invalidate();
    }

    private PathEffect createPathEffect(float pathLength, float phase, float offset) {
        return new PathEffect(new float[]{phase * pathLength, pathLength}, 0);
    }


    @Override
    public void drawLabels(Canvas canvas, ChartData chartData, Axis axisY) {
        if (isAnimateEnd)
            super.drawLabels(canvas, chartData, axisY);
    }
}
